﻿using FreeSql;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpLogging;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Serilog;
using Serilog.Configuration;
using Serilog.Context;
using Serilog.Core;
using Serilog.Events;
using Serilog.Sinks.Fsql;
using Serilog.Sinks.PeriodicBatching;
using System.Text;
using System;
using IBatchedLogEventSink = Serilog.Sinks.PeriodicBatching.IBatchedLogEventSink;

namespace LogExtensions
{
    public static class LogExtension
    {
        public static void AddLogger(this IServiceCollection services, IConfiguration configuration)
        {
            var logConfig = configuration.GetSection("LogConfig").Get<LogConfig>() ?? new LogConfig();

            services.Configure<LogConfig>(configuration.GetSection("LogConfig"));

            var str = (configuration["DbConfig:ConnectionString"]) ?? "";
            var dt = configuration["DbConfig:DataType"];


            services.AddSerilog(op =>
            {
                op.ReadFrom.Configuration(configuration)
                .Filter
                .ByExcluding((e) =>
                e.Properties.ContainsKey("RequestPath")
                && (logConfig.Includes != null && !logConfig.Includes.Any(x => e.Properties["RequestPath"].ToString().ToLower().Contains(x.ToLower()))
                && logConfig.Excludes != null && logConfig.Excludes.Any(x => e.Properties["RequestPath"].ToString().ToLower().Contains(x.ToLower())
                )));

                if (logConfig != null && logConfig.Shows.Any(x => x == LogShows.Console))
                {
                    op.WriteTo.Async(a => a.Console(outputTemplate: "{Timestamp:HH:mm:ss} || {Level}   || {Message} || {Exception} ||end {NewLine}"));
                }
                if (logConfig != null && logConfig.Shows.Any(x => x == LogShows.File))
                {
                    op.WriteTo.Async(a => a.File(
                        $"{AppContext.BaseDirectory}Logs/.log", rollingInterval: RollingInterval.Day,
                          rollOnFileSizeLimit: true, fileSizeLimitBytes: 50485760,
                        outputTemplate: "{Timestamp:HH:mm:ss} ||   {Level}   || {Message} || {Exception} ||end {NewLine}"
                        ));

                }
                if (logConfig != null && logConfig.Shows.Any(x => x == LogShows.DataBase))
                {
                    op.WriteTo.Async(a => a.Map(keyPropertyName: "name",
                             defaultKey: "0", configure: (name, wt) =>
                             {
                                 int.TryParse(dt, out int dataType);
                                 wt.Async(lc => lc.FsqlSink(
                                  options: new FreeSqlSinkOptions
                                  {
                                      ConnectionString = string.IsNullOrWhiteSpace(logConfig.ConnectionString) ? str : logConfig.ConnectionString,
                                      ColumnNameStyle = FreeSql.Internal.NameConvertType.PascalCaseToUnderscoreWithLower,
                                      DataType = string.IsNullOrWhiteSpace(logConfig.ConnectionString) ? (DataType)dataType : logConfig.DataType,
                                      EnableShard = logConfig.EnableShard,
                                      ShardTableClearHour = logConfig.ShardTableClearHour,
                                      UseBulk = logConfig.UseBulk,
                                      TableName = $"{logConfig.TableName}_{name}",
                                      ShardReserveTableDay = logConfig.ShardReserveTableDay,
                                  }, new PeriodicBatchingSinkOptions
                                  {
                                      BatchSizeLimit = 1000,
                                      EagerlyEmitFirstEvent = true,
                                      QueueLimit = 100,
                                  }),
                                  100, true);
                             }));

                }

            });

            if (logConfig.HttpLog)
            {
                services.AddHttpLogging(logging =>
                {
                    logging.LoggingFields = HttpLoggingFields.All;
                    logging.RequestBodyLogLimit = 4096;
                    logging.ResponseBodyLogLimit = 4096;
                    logging.CombineLogs = logConfig.CombineLogs;
                });
                services.AddHttpLoggingInterceptor<HttpLoggingInterceptor>();

            }
        }

        /// <summary>
        /// fsql适配器
        /// </summary>
        /// <param name="loggerConfiguration"></param>
        /// <param name="options"></param>
        /// <param name="periodicBatchingSinkOptions"></param>
        /// <param name="restrictedToMinimumLevel"></param>
        /// <param name="levelSwitch"></param>
        /// <returns></returns>
        public static LoggerConfiguration FsqlSink(
          this LoggerSinkConfiguration loggerConfiguration,
          FreeSqlSinkOptions options,
           PeriodicBatchingSinkOptions periodicBatchingSinkOptions = null,
             LogEventLevel restrictedToMinimumLevel = 0, LoggingLevelSwitch levelSwitch = null
          )
        {
            var val = new FreeSqlSink(options);

            return loggerConfiguration.Sink(new PeriodicBatchingSink((IBatchedLogEventSink)(val), periodicBatchingSinkOptions), restrictedToMinimumLevel, levelSwitch);
        }
        public static void UseHttpLogger(this WebApplication app)
        {

            var config = app.Configuration.GetSection("LogConfig").Get<LogConfig>() ?? new LogConfig();
            if (config.HttpLog)
            {

                /*app.UseSerilogRequestLogging(options =>
                {
                    options.MessageTemplate = "{Scheme}:Elapsed:{Elapsed:0.0000}ms StatusCode:{StatusCode} {RequestMethod} {RequestPath} {RequestHost} {RequestBody} {RequestQuery} {RequestHeaders} {ResponseBody}";
                });*/
                //  app.UseMiddleware<HttpLogMiddleware>();
                app.UseHttpLogging();
            }

            //
        }

    }
}
